// 我们前面碰到的 String 和 Vec<T> 就是一种智能指针。
// 我们来看标准库代码中 String  的定义和 Vec<T> 的定义。

// pub struct String {
//     vec: Vec<u8>,
// }

// pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")]
// A: Allocator = Global> {
//     buf: RawVec<T, A>,
//     len: usize,
// }


// derive v.得到；获得；(使)产生；取得；(使)起源
#[derive(Debug,Clone)]
struct Point {
    x: u32,
    y: u32,
}

#[cfg(test)]
mod tests {
    use crate::smart_point::Point;

    fn foo() -> String {
        let s = "abc".to_string();
        s // 这里的s 被调用就被销毁，所有权发生啦转移
    }
    // 下面的代码不允许，
    // fn foo2() -> &u32 {
    //     let i = 100u32;
    //     &i
    // }

    fn foo_box() -> Box<u32> {
        // 编译期间已知尺寸的类型实例会默认创建在栈上
        let i = 100u32;
        // 强行 copy 了一份并放在堆上某个地址，
        // 然后 Box 指针指向这个地址。
        Box::new(i) //把 i 实例强行按位复制了一份
    }


    #[test]
    fn main() {
        // foo.s 所有权发生转移
        let _s = foo();
        assert_eq!(_s, "abc");

        let _s = foo();
        assert_eq!(_s, "abc");
    }

    fn box_point() -> Box<Point> {
        let b = Point { x: 10, y: 20 };
        Box::new(b)
    }

    #[test]
    fn fetch_box() {
        let p1 = box_point();
        println!("boxed : {:?}", p1);
        let p2 = *p1; //解引用, box就发生了转移
        assert_eq!(p2.x, 10);
        assert_eq!(p2.y, 20);
        println!("un boxed: {:?}", p2);
        // println!("point: {:?}, Box<Point>: {:?}", p2, p1);
    }

    #[test]
    fn can_change_box() {
        let mut boxed: Box<Point> = Box::new(Point { x: 10, y: 20 });
        *boxed = Point {
            // 这一行，使用解引用操作更新值
            x: 100,
            y: 200,
        };
        println!("{:?}", boxed);
        assert_eq!(boxed.x, 100);
    }

    #[test]
    // #[should_panic]
    fn clone_box() {
        //Box 能否 Clone，需要看 T 是否实现了 Clone
        let mut boxed: Box<Point> = Box::new(Point { x: 10, y: 20 });
        let mut another_boxed = boxed.clone(); // 克隆
        *another_boxed = Point { x: 100, y: 200 }; // 修改新的一份值
        println!("{:?}", boxed); // 打印原来一份值
        println!("{:?}", another_boxed); // 打印新的一份值
        assert_eq!(another_boxed.x, 100);
    }
}